home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
program
/
qlib205.zip
/
QLIB.ZIP
/
SRC
/
MATH
/
MATH_COM.ASM
< prev
next >
Wrap
Assembly Source File
|
1997-04-13
|
11KB
|
413 lines
; Math Library to be used in C programs
;after finishing up the new func I found that BC LIBs suck!
; they had a few bugs, such as INF equal to 1.76645645e308 or so, and
; reports an error when pow(0,0) is used which returns 1 but should not
; be an error (at least according to their online help)
.data?
align 4
result REAL8 ?
tmpd dd ?
tmpr real8 ?
tmpr2 real8 ?
tmpw dw ?
sign db ?
.const
_ZERO real8 0.0
EXP_MAX real8 709.7827128933839
ten REAL8 10.0
;FIX : v2.00 Beta #7 : these were all backwards and messed up
rnd_0 label word ;round towards 0
db 7fh,1111b
rnd_up label word ;round up
db 7fh,1011b
rnd_dw label word ;round down
db 7fh,0111b
cw_def label word ;default rounding (to nearest or even)
db 7fh,0011b
.code
RETURN macro ;saves return value (on FPU stack) in Watcom or Borland style
ifdef _WC_
fstp result
fwait
mov eax,dptr[result]
mov edx,dptr[result+4]
ret
else
fwait
ret
endif
endm
LOADF macro ;loads Watcom return into FPU stack
ifdef _WC_
mov dptr[result],eax
mov dptr[result+4],edx
fld result
fwait
endif
endm
CHKF macro ;sets errno based on value on top of FPU stack
fxam
fstsw ax
fwait
and ah,01000111b
.if ah == 001b || ah == 011b
;+/-NAN
mov errno,EDOM
.elseif ah == 101b || ah == 111b
;+/-INF
mov errno,ERANGE
.endif
endm
sin proc,a:REAL8
fld a
fsin
fstsw ax
.if ax&4 ;mask C2
mov errno,ERANGE
.else
mov errno,0
.endif
RETURN
sin endp
cos proc,a:REAL8
fld a
fcos
fstsw ax
.if ax&4 ;mask C2
mov errno,ERANGE
.else
mov errno,0
.endif
fwait
RETURN
cos endp
tan proc,a:REAL8
fld a
fsincos
fstsw ax
.if ax&4 ;mask C2
mov errno,ERANGE
.else
mov errno,0
.endif
fdivp st(1),st
RETURN
tan endp
ftol proc,a:REAL8
fld a
__ftol::
fistp dptr[result]
fwait
mov eax,dptr[result]
ret
ftol endp
f_abs proc,a:REAL8
and bptr [a+7],7fh
fld a
RETURN
f_abs endp
ceil proc,a:REAL8
fldcw rnd_up
fld a
frndint
fldcw cw_def
RETURN
ceil endp
floor proc,a:REAL8
fldcw rnd_dw
fld a
frndint
fldcw cw_def
RETURN
floor endp
;FIX : v2.00 Beta #7 : now supports exp forms
atof proc,a:dword
local _neg:byte
pushad
mov esi,a
mov _neg,0
fldz
xor eax,eax ;keep high part clear
@@:
lodsb
.if al==32
jmp @b
.endif
.if al=='-'
inc _neg
lodsb
.endif
.if al=='e' || al=='E'
jmp doexp ; still have to get exp even though 0**anything is zero
.endif ; cause _str2num_siz_ must be updated
.if al=='.'
jmp dodec
.endif
@@:
.if (al>='0') && (al<='9')
fmul ten
sub al,'0'
mov tmpd,eax
fiadd tmpd
fwait
.elseif al=='.'
jmp dodec
.elseif al=='e' || al=='E'
jmp doexp
.else
jmp done
.endif
lodsb
jmp @b
dodec:
fldz ;decimal part
mov edi,esi ;save EDI for stop pt
lodsb
.if ! ( (al>='0') && (al<='9') )
fstp tmpr ;ignore!
fwait
;FIX v 2.00 Beta #8 : this was not poped off properly
.if al=='e' || al=='E'
jmp doexp
.endif
jmp done ;no numbers after .
.endif
@@:
.if (al>='0') && (al<='9')
lodsb
jmp @b
.endif
push esi
push ax ;save last thing (if it's 'e' then there is an exp part)
dec esi ;go back
dec esi
@@: ;go until ESI==EDI
mov al,[esi]
sub al,'0'
mov tmpd,eax
fiadd tmpd
fdiv ten
fwait
.if esi>edi
dec esi
jmp @b
.endif
faddp st(1),st
pop ax
pop esi
.if !(al=='e' || al=='E')
jmp done
.endif
doexp:
;esi=>char after e
.if bptr[esi]=='-'
mov ch,1
inc esi
.else
mov ch,0
.endif
xor eax,eax
xor ebx,ebx
@@:
lodsb
.if !((al >= '0') && (al<= '9'))
jmp expdone
.endif
sub al,'0'
imul ebx,ebx,10
add ebx,eax
jmp @b
expdone:
fstp tmpr ;save #
mov tmpd,ebx
fild tmpd
fstp tmpr2
fwait
callp pow,ten,tmpr2
LOADF ;st(1)
fld tmpr ;st ;reload #
.if ch==1 ;neg
fxch
fdivp st(1),st
.else ;pos
fmulp st(1),st
.endif
done:
.if _neg
fchs
.endif
mov eax,esi
sub eax,a
dec eax ;minus the last char not used (ie: NULL)
mov _str2num_siz_,eax ;FIX : v2.00 Beta #7 : this was not set right
popad
RETURN
atof endp
exp PROC, val:REAL8
mov [errno], 0 ; clear matherror
fld val ; load the value
fcom EXP_MAX ; exceeded maximum?
fstsw ax ; save status word in AX
fwait ; wait this shit be idle
sahf ; load flags with it
jna @f
mov [errno], ERANGE ; set matherror from QLIB
@@:
fldl2e ; load log 2 (base e)
fmulp st(1), st(0) ; mul them
fld st(0) ; copy st(0) to st(1)
frndint ; rount st(0)
fxch st(1) ; xchange st(1) for st(0)
fsub st(0), st(1) ; sub rounded from unrounded
f2xm1 ; calc 2^x-1
fld1 ; load 1.00
faddp st(1), st(0) ; add 1.00 to st(1)
fscale ; exponential function of a
ffree st(1) ; remove rounded value
RETURN
exp ENDP
log proc, val:REAL8
mov [errno], 0 ; clear matherror
fld val ; load the value
ftst ; compare with zero
fstsw ax ; save status word in AX
fwait ; wait this shit be idle
sahf ; load flags with it
.if carry? ;jb @@negative ; jump if value < 0
mov [errno], EDOM ; domain error
.endif
.if zero? ;je @@zero ; jump if zero
mov [errno], ERANGE ; range error
.endif
fldln2 ; load natural log of 2
fxch st(1) ; xchange it with value
fyl2x ; calc y=log2(x)
RETURN
log ENDP
log10 PROC, val:REAL8
mov [errno], 0 ; clear matherror
fld val ; load the value
ftst ; compare with zero
fstsw ax ; save status word in AX
fwait ; wait this shit be idle
sahf ; load flags with it
.if carry? ;jb @@negative ; jump if value < 0
mov [errno], EDOM ; domain error
.endif
.if zero? ;je @@zero ; jump if zero
mov [errno], ERANGE ; range error
.endif
fldlg2 ; load log of 2
fxch st(1) ; xchange it wih value
fyl2x ; calc y=log2(x)
RETURN
log10 ENDP
log2 PROC, val:REAL8
mov [errno], 0 ; clear matherror
fld val ; load the value
ftst ; compare with zero
fstsw ax ; save status word in AX
fwait ; wait this shit be idle
sahf ; load flags with it
.if carry? ;jb @@negative ; jump if value < 0
mov [errno], EDOM ; domain error
.endif
.if zero? ;je @@zero ; jump if zero
mov [errno], ERANGE ; range error
.endif
fld1 ; load 1
fxch st(1) ; xchange it with value
fyl2x ; calc y=log2(x)
RETURN
log2 ENDP
pow PROC, val:REAL8, power:REAL8
mov errno,0
fld val
fcomp _ZERO
fstsw ax
fwait
sahf
.if zero?
fld power
fcomp _ZERO
fstsw ax
fwait
sahf
.if zero? ;this is ANSI C specs
fld1 ;load one! (in reality 0**0 is INF - o well)
RETURN
.endif
fldz ;0**power = 0 always
RETURN
.endif
fld power
fcomp _ZERO
fstsw ax
fwait
sahf
.if zero? ;this is ANSI C specs
fld1 ;load one!
RETURN
.endif
callp log,val ; calculate log of val
LOADF
fld power ; load power
fmulp st(1), st(0) ; multiply them
fstp result ; save result
callp exp,result ; calculate exp func of result
LOADF
CHKF ;setup error codes
RETURN
pow ENDP
sqrt PROC, val:REAL8
mov [errno], 0 ; clear matherror
fld val ; load val
ftst ; compare with zero
fstsw ax ; save status word in AX
fwait ; wait this shit be idle
sahf ; load flags with it
.if carry? ; jump if value < 0
mov [errno], EDOM ; uh-oh. val < 0 = domain err!
fsqrt ;will return -NAN ; square root of st(0)
fabs ;make sure it's +NAN
.else
fsqrt ; square root of st(0)
.endif
RETURN
sqrt ENDP